﻿using System;
using System.Text;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Linq;
using System.Collections.Generic;

namespace HL7toXDocumentParser
{
    /// <summary>
    /// HL7解析器
    /// </summary>
    public static class HL7Converter
    {
        private static Parser hl7Parser = new Parser();
        private static XDocument _xmlDoc;

        /// <summary>
        /// 把HL7信息转成Json形式
        /// </summary>
        /// <param name="sHL7"></param>
        /// <returns></returns>
        //public static string ConvertToJson(string sHL7)
        //{
        //    var document = ConvertToXmlObject(sHL7);

        //    // Return a JSON-encoded version of the document
        //    return Newtonsoft.Json.JsonConvert.SerializeXmlNode(document);
        //}
        //----------------------------------------------------------------------------------------------
        /// <summary>
        /// 把HL7信息转成XML形式
        /// 分隔顺序 \n,|,~,^,&
        /// </summary>
        /// <param name="sHL7">HL7字符串</param>
        /// <returns></returns>
        public static string ConvertToXml(string sHL7)
        {
            _xmlDoc = ConvertToXmlObject(sHL7);
            return _xmlDoc.ToString();
        }
        /// <summary>
        /// Converts an HL7 message into an XML representation of the same message.
        /// </summary>
        /// <param name="sHL7"></param>
        /// <returns></returns>
        public static XDocument ConvertToXmlObject(string sHL7)
        {
            _xmlDoc = hl7Parser.Parse(sHL7);
            return _xmlDoc;
        }

        //----------------------------------------------------------------------------------------------
        /// <summary>
        ///  按文档顺序返回此文档或元素的已筛选的子代元素集合
        /// </summary>
        /// <param name="xdoc"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IEnumerable<XElement> GetSubXElement(string name)
        {
            return GetSubXElement(_xmlDoc, name);
        }
        public static string GetText(string path)
        {
            return GetText(_xmlDoc, path);
        }
        public static string GetText(string path, int index)
        {
            return GetText(_xmlDoc, path, index);
        }
        public static String[] GetTexts(string path)
        {
            return GetTexts(_xmlDoc, path);
        }
        //----------------------------------------------------------------------------------------------
        /// <summary>
        /// 把HL7信息转成 XDocument 形式
        /// </summary>
        /// <param name="sHL7"></param>
        /// <returns></returns>
        public static bool Parse(string sHL7)
        {
            _xmlDoc = hl7Parser.Parse(sHL7);
            return _xmlDoc != null;
        }
        /// <summary>
        ///  按文档顺序返回此文档或元素的已筛选的子代元素集合
        /// </summary>
        /// <param name="xdoc"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IEnumerable<XElement> GetSubXElement(this XContainer xdoc, string name)
        {
            return xdoc?.Descendants(name);
        }
        /// <summary>
        /// 根据元素名称返回第一个名称相符的值
        /// </summary>
        /// <param name="xdoc"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetText(this XContainer xdoc, string name)
        {
            return (from elem in GetSubXElement(xdoc, name) select elem.Value)?.FirstOrDefault();
        }

        public static string GetText(this XContainer xdoc, string name, int index)
        {
            var nodes = GetSubXElement(xdoc, name)?.First()?.Elements()?.ToList();
            if (index <= nodes?.Count)
            {
                return nodes[index].Value;
            }
            else
            {
                return null;
            }
        }

        public static string[] GetTexts(this XContainer xdoc, string name)
        {
            var nodes = GetSubXElement(xdoc, name)?.First()?.Elements()?.ToList();
            if (nodes?.Count > 0)
            {
                var arr = new string[nodes.Count];
                int index = 0;
                foreach (var node in nodes)
                {
                    arr[index++] = node.Value;
                }
                return arr;
            }
            else
            {
                return new string[0];
            }
        }

        public static string FormatXml(string sUnformattedXml)
        {

            XmlDocument xd = new XmlDocument();
            xd.LoadXml(sUnformattedXml);
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            XmlTextWriter xtw = null;
            try
            {
                xtw = new XmlTextWriter(sw);
                xtw.Formatting = Formatting.Indented;
                xtw.Indentation = 1;
                xtw.IndentChar = '\t';
                xd.WriteTo(xtw);
            }
            finally
            {
                if (xtw != null)
                    xtw.Close();
            }
            return sb.ToString();
        }
    }

    /*测试方法：

    string hl7 = @"MSH|^~\&|MPCoagu|Mindray|||20141114104119||ORU^R01|5|P|2.3.1||||||UNICODE
PID|1||no123^^^^MR||^name||20090105|男
PV1|1||dept^^b102|||||||||||||||||charge
OBR|1||1|00001^Automated Count^99MRC|||20141113195229|||sender|||ganmao|20140811||||||1||20141114104032||HM||||Admin||||Admin
OBX|1|NM|30525-0^Age^LN||5|yr|||||F
OBX|2|NM|14979-9^APTT^LN||10.00|Sec|24.00-38.00||||F
OBX|3|NM|6301-6^PT_INR^LN||0.50|INR|0.75-1.35||||F
OBX|4|NM|5902-2^PT^LN||12.00|Sec|11.00-16.00||||F
OBX|5|NM|3243-3^TT^LN||9.00|Sec|8.00-16.00||||F
OBX|6|NM|3255-7^FIB^LN||2.20|g/L|2.00-4.00||||F
OBX|7|NM|29263-1^FDP^LN||0.00|μg/ml|0.00-0.01||||F
OBX|8|NM|7799-0^D_D^LN||0.00|μg/ml|0.00-0.00||||F
OBX|9|NM|3174-0^AT_III^LN||82.00|%|81.50-121.30||||F";

    var sHL7asXml = HL7Converter.ConvertToXml(hl7);
    var xmlObject = HL7Converter.ConvertToXmlObject(hl7);

    HL7Converter.Parse(hl7);
    var MSH_7 = HL7Converter.GetText("MSH.7");
    var MSH_18 = HL7Converter.GetText("MSH.18");
    var PID_3_1 = HL7Converter.GetText("PID.3.1");
    var OBR_4 = HL7Converter.GetTexts("OBR.4");
    var OBR_4_2 = HL7Converter.GetText("OBR.4", 1);
    var OBR_4_3 = HL7Converter.GetText("OBR.4.3");
       
    Console.WriteLine($"MSH_7={MSH_7},MSH_18={MSH_18},PID_3_1={PID_3_1},OBR_4={string.Join(";", OBR_4)},OBR_4_2={OBR_4_2},OBR_4_3={OBR_4_3}");

    var OBXs = HL7Converter.GetSubXElement("OBX");
    foreach (var obx in OBXs)
    {
        var OBX_1 = HL7Converter.GetText(obx,"OBX.1");
        var OBX_3_1 = HL7Converter.GetText(obx, "OBX.3",0);

        Console.WriteLine($"OBX_1={OBX_1},OBX_3_1={OBX_3_1}");
    }
    */
}
